package com.wwdeng.smart.video

import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.SurfaceTexture
import android.graphics.Typeface
import android.media.AudioFormat
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.DisplayMetrics
import android.util.Log
import android.view.Surface
import android.view.TextureView
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import com.alibaba.fastjson.JSONArray
import com.tencent.iot.video.link.entity.DeviceStatus
import com.tencent.iot.video.link.util.audio.AudioRecordUtil
import com.tencent.xnet.XP2P
import com.tencent.xnet.XP2PCallback
import com.wt.monitor.ui.video.utils.Command
import com.wwdeng.smart.app.AppData
import com.wwdeng.smart.base.BaseAct
import com.wwdeng.smart.databinding.UiVideoPreviewBinding
import com.wwdeng.smart.utils.TitleBarUtil
import com.wwdeng.smart.video.event.ActionRecord
import com.wwdeng.smart.video.event.EventPresenter
import com.wwdeng.smart.video.event.EventView
import com.wwdeng.smart.video.iview.IPreviewView
import com.wwdeng.smart.video.presenter.PreviewPresenter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.json.JSONObject
import tv.danmaku.ijk.media.player.IMediaPlayer
import tv.danmaku.ijk.media.player.IjkMediaPlayer
import java.util.Date

/**
 * android
 * @Author：wwdeng
 * @CreateTime：2024/9/15 16:16
 * <pre>
 * 视频预览、回放
 * </pre>
 */

private var keepPlayThreadLock = Object()
@Volatile
private var keepAliveThreadRuning = true

open class VideoPreviewAct: BaseAct(), IPreviewView, TextureView.SurfaceTextureListener, EventView,
    XP2PCallback, IMediaPlayer.OnInfoListener,CoroutineScope by MainScope() {
    private lateinit var binding: UiVideoPreviewBinding
    private var presenter: PreviewPresenter? = null

    private lateinit var eventPresenter: EventPresenter
    private lateinit var videoPlayer : IjkMediaPlayer
    private lateinit var surface: Surface
    private lateinit var audioRecordUtil: AudioRecordUtil
    private var urlPrefix = ""

    private var orientationV = true
    private var screenWidth = 0
    private var screenHeight = 0

    companion object {
        private const val INTENT_ACCESS_ID = "accessId"
        private const val INTENT_ACCESS_TOKEN = "accessToken"
        private const val INTENT_PRODUCT_ID = "productId"
        fun startPreviewActivity(context: Context?,accId: String,accToken: String,pId: String) {
            context?:let { return }
            val intent = Intent(context, VideoPreviewAct::class.java)
            intent.putExtra(INTENT_ACCESS_ID, accId)
            intent.putExtra(INTENT_ACCESS_TOKEN, accToken)
            intent.putExtra(INTENT_PRODUCT_ID, pId)
            context.startActivity(intent)
        }
    }

    override fun getRootView(): View {
        binding = UiVideoPreviewBinding.inflate(layoutInflater)
        return binding.root
    }

    override fun initView() {
        binding.titleLayout.setPadding(0, TitleBarUtil.getStatusBarHeight(),0,0)
        binding.videoView.surfaceTextureListener = this

        eventPresenter = EventPresenter(this)
        binding.txtTitle.text = AppData.deviceName
        eventPresenter.setDeviceName(AppData.deviceName)
        eventPresenter.setChannel(0)
        eventPresenter.setAccessId(AppData.accessId)
        eventPresenter.setAccessToken(AppData.accessToken)
        eventPresenter.setProductId(AppData.productId)
        eventPresenter.getEventsData(Date())

        audioRecordUtil = AudioRecordUtil(this, "${AppData.productId}/${eventPresenter.getDeviceName()}", 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)

        XP2P.setCallback(this)
        XP2P.startService(this, "${AppData.productId}/${eventPresenter.getDeviceName()}", AppData.productId, eventPresenter.getDeviceName())

        val wm = this.getSystemService(WINDOW_SERVICE) as WindowManager
        val dm = DisplayMetrics()
        wm.defaultDisplay.getMetrics(dm)
        val width = dm.widthPixels // 屏幕宽度（像素）
        val height = dm.heightPixels // 屏幕高度（像素）
        val density = dm.density // 屏幕密度（0.75 / 1.0 / 1.5）
        screenWidth = (width / density).toInt() // 屏幕宽度(dp)
        screenHeight = (height / density).toInt() // 屏幕高度(dp)
    }

    override fun initListener() {
        //返回
        binding.imgBack.setOnClickListener {
            finish()
        }
        //实时视频
        binding.realTimeLayout.setOnClickListener {
            presenter!!.loadRealTimeVideoAction()
        }

        //云回放
        binding.cloudLayout.setOnClickListener{
            presenter!!.loadCloudVideoListAction()
        }

        //卡回放
        binding.cardLayout.setOnClickListener {
            presenter!!.loadCardVideoListAction()
        }

    }

    override fun initData() {
        presenter = PreviewPresenter(this)
        //默认加载实时视频
        presenter!!.loadRealTimeVideoAction()

        if (TextUtils.isEmpty(eventPresenter.getDeviceName())) return
        videoPlayer = IjkMediaPlayer()
        videoPlayer.setOnInfoListener(this)
    }

    /**
     * 默认都不选中
     */
    override fun showCheckTypeNormal() {
        binding.txtReaTime.setTypeface(Typeface.DEFAULT,Typeface.NORMAL)
        binding.txtReaTime.setTextColor(Color.parseColor("#999999"))
        binding.vRealTime.visibility = View.INVISIBLE

        binding.txtCloudRecording.setTypeface(Typeface.DEFAULT,Typeface.NORMAL)
        binding.txtCloudRecording.setTextColor(Color.parseColor("#999999"))
        binding.vCloudRecording.visibility = View.INVISIBLE

        binding.txtCardRecording.setTypeface(Typeface.DEFAULT,Typeface.NORMAL)
        binding.txtCardRecording.setTextColor(Color.parseColor("#999999"))
        binding.vCardRecording.visibility = View.INVISIBLE
    }

    /**
     * 实时
     */
    override fun showRealTimeViews(videoUrl: String) {
        binding.txtReaTime.setTypeface(Typeface.DEFAULT,Typeface.BOLD)
        binding.txtReaTime.setTextColor(Color.parseColor("#ff0079fe"))
        binding.vRealTime.visibility = View.VISIBLE

        supportFragmentManager
            .beginTransaction()
            .replace(binding.containerLayout.id, RealTimeFragment(this))
            .commitAllowingStateLoss()

        Handler(Looper.getMainLooper()).postDelayed({
            onStartPlayer()
        },3000)
    }

    /**
     * 云回放
     */
    override fun showRecordingCloudViews(videoList: ArrayList<JSONObject>) {
        binding.txtCloudRecording.setTypeface(Typeface.DEFAULT,Typeface.BOLD)
        binding.txtCloudRecording.setTextColor(Color.parseColor("#ff0079fe"))
        binding.vCloudRecording.visibility = View.VISIBLE

        supportFragmentManager
            .beginTransaction()
            .replace(binding.containerLayout.id, RecordingFragment(this,videoList))
            .commitAllowingStateLoss()
    }

    /**
     * 卡回放
     */
    override fun showRecordingCardViews(videoList: ArrayList<JSONObject>) {
        binding.txtCardRecording.setTypeface(Typeface.DEFAULT,Typeface.BOLD)
        binding.txtCardRecording.setTextColor(Color.parseColor("#ff0079fe"))
        binding.vCardRecording.visibility = View.VISIBLE

        supportFragmentManager
            .beginTransaction()
            .replace(binding.containerLayout.id, RecordingFragment(this,videoList))
            .commitAllowingStateLoss()
    }

    /**
     * 播放
     */
    private fun onStartPlayer(){

        Thread(Runnable {
            val id = "${AppData.productId}/${eventPresenter.getDeviceName()}"
            val ret = XP2P.setParamsForXp2pInfo(id, AppData.accessId, AppData.accessToken, AppData.xp2pInfo)
            if (ret != 0) {
                launch(Dispatchers.Main) {
                    val errInfo: String
                    if (ret.toString() == "-1007") {
                        errInfo = "APP SDK 版本与设备端 SDK 版本号不匹配，版本号需前两位保持一致"
                    } else {
                        errInfo = "$id 连接错误码 ${ret}，通道断开"
                    }
                    Toast.makeText(this@VideoPreviewAct, errInfo, Toast.LENGTH_SHORT).show()
                }
                return@Runnable
            }
            XP2P.delegateHttpFlv(id)?.let {
                urlPrefix = it
                if (!TextUtils.isEmpty(urlPrefix)) {
                    videoPlayer.let {
                        resetPlayer()
                        keepPlayerplay(id)
                    }
                }
            }
        }).start()
    }

    private fun resetPlayer() {
        setPlayerUrl(Command.getVideoHightQualityUrlSuffix(eventPresenter.getChannel()))
//        when (binding.tvVideoQuality.text.toString()) {
//            getString(R.string.video_quality_high_str) -> setPlayerUrl(Command.getVideoSuperQualityUrlSuffix(presenter.getChannel()))
//            getString(R.string.video_quality_medium_str) -> setPlayerUrl(Command.getVideoHightQualityUrlSuffix(presenter.getChannel()))
//            getString(R.string.video_quality_low_str) -> setPlayerUrl(Command.getVideoStandardQualityUrlSuffix(presenter.getChannel()))
//        }
    }

    open fun setPlayerUrl(suffix: String) {
        videoPlayer.release()
        launch(Dispatchers.Main) {
            binding.videoLayout.removeView(binding.videoView)
            binding.videoLayout.addView(binding.videoView, 0)

            videoPlayer = IjkMediaPlayer()
            videoPlayer.setOnInfoListener(this@VideoPreviewAct)
            videoPlayer.let {
                val url = urlPrefix + suffix
                it.reset()

                it.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "analyzemaxduration", 100)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "probesize", 50 * 1024)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "packet-buffering", 0)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 1)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "threads", 1)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "sync-av-start", 0)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec",1)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1)
                it.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1)

                it.setFrameSpeed(1.5f)
                while (!::surface.isInitialized) {
                    delay(50)
                    Log.e("TAG","delay for waiting surface.")
                }
                it.setSurface(surface)
                it.dataSource = url

                it.prepareAsync()
                it.start()
            }
        }
    }

    private fun keepPlayerplay(id: String?) {
        if (TextUtils.isEmpty(id)) return
        val accessId = AppData.accessId
        val accessToken = AppData.accessToken
        // 开启守护线程
        Thread{
            val objectLock = Object()
            while (true) {
                Log.d("TAG", "id=${id} keepAliveThread wait disconnected msg")
                synchronized(keepPlayThreadLock) {
                    keepPlayThreadLock.wait()
                }
                Log.d("TAG", "id=${id} keepAliveThread do not wait and keepAliveThreadRuning=${keepAliveThreadRuning}")
                if (!keepAliveThreadRuning) break //锁被释放后，检查守护线程是否继续运行

                // 发现断开尝试恢复视频，每隔一秒尝试一次
                Log.d("TAG", "====开始尝试重连...")
                XP2P.stopService(id)
                while (XP2P.startService(this, id, AppData.productId, eventPresenter.getDeviceName())!=0
                    || XP2P.setParamsForXp2pInfo(id, accessId, accessToken, AppData.xp2pInfo) != 0
                    || getDeviceStatus(id) != 0) {
                    XP2P.stopService(id)
                    synchronized(objectLock) {
                        objectLock.wait(500)
                    }
                    Log.d("TAG", "====正在重连...")
                }
//                connectStartTime = System.currentTimeMillis()

                Log.d("TAG", "====尝试拉流...")
                XP2P.delegateHttpFlv(id)?.let {
                    urlPrefix = it
                    if (!TextUtils.isEmpty(urlPrefix)) resetPlayer()
                }
            }
        }.start()
    }

    private fun getDeviceStatus(id: String?): Int {
//        var command: ByteArray? = null
//        when (binding.tvVideoQuality.text.toString()) {
//            getString(R.string.video_quality_high_str) -> {
//                command = "action=inner_define&channel=0&cmd=get_device_st&type=live&quality=super".toByteArray()
//            }
//            getString(R.string.video_quality_medium_str) -> {
//                command = "action=inner_define&channel=0&cmd=get_device_st&type=live&quality=high".toByteArray()
//            }
//            getString(R.string.video_quality_low_str) -> {
//                command = "action=inner_define&channel=0&cmd=get_device_st&type=live&quality=standard".toByteArray()
//            }
//        }
        val command = "action=inner_define&channel=0&cmd=get_device_st&type=live&quality=high".toByteArray()
        val reponse = XP2P.postCommandRequestSync(id, command, command!!.size.toLong(), 2 * 1000 * 1000)
        if (!TextUtils.isEmpty(reponse)) {
            val deviceStatuses: List<DeviceStatus> = JSONArray.parseArray(reponse, DeviceStatus::class.java)
            // 0   接收请求
            // 1   拒绝请求
            // 404 error request message
            // 405 connect number too many
            // 406 current command don't support
            // 407 device process error
            if (deviceStatuses.isNotEmpty()) {
                runOnUiThread {
                    when (deviceStatuses[0].status) {
                        0 -> Toast.makeText(this, "设备状态正常", Toast.LENGTH_SHORT).show()
                        1 -> Toast.makeText(this, "设备状态异常, 拒绝请求: $reponse", Toast.LENGTH_SHORT).show()
                        404 -> Toast.makeText(this, "设备状态异常, error request message: $reponse", Toast.LENGTH_SHORT).show()
                        405 -> Toast.makeText(this, "设备状态异常, connect number too many: $reponse", Toast.LENGTH_SHORT).show()
                        406 -> Toast.makeText(this, "设备状态异常, current command don't support: $reponse", Toast.LENGTH_SHORT).show()
                        407 -> Toast.makeText(this, "设备状态异常, device process error: $reponse", Toast.LENGTH_SHORT).show()
                    }
                }
                return deviceStatuses[0].status
            } else {
                runOnUiThread {
                    Toast.makeText(this, "获取设备状态失败", Toast.LENGTH_SHORT).show()
                }
                return -1
            }
        }
        return -1
    }

    override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
        surface.let {
            this.surface = Surface(surface)
            videoPlayer.setSurface(this.surface)
        }
    }

    override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
        val layoutParams = binding.videoView.layoutParams
        if (orientationV) {
            layoutParams.width = (videoPlayer.videoWidth * (screenWidth * 16 / 9)) / videoPlayer.videoHeight
            layoutParams.height = layoutParams.height
        } else {
            layoutParams.width = (videoPlayer.videoWidth * height) / videoPlayer.videoHeight
        }
        binding.videoView.layoutParams = layoutParams
    }

    override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
        return false
    }

    private var firstIn = true
    override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
        if (orientationV && firstIn) {
            val layoutParams = binding.videoView.layoutParams
            layoutParams.width = (videoPlayer.videoWidth * (screenWidth * 16 / 9)) / videoPlayer.videoHeight
            layoutParams.height = layoutParams.height
            binding.videoView.layoutParams = layoutParams
            firstIn = false
        }
    }

    override fun eventReady(events: MutableList<ActionRecord>) {
        if (events.size <= 0) {
            Log.e("TAG","暂无数据")
        }
    }

    override fun fail(msg: String?, errorCode: Int) {
    }

    override fun commandRequest(id: String?, msg: String?) {
    }

    override fun xp2pEventNotify(id: String?, msg: String?, event: Int) {
        Log.e("TAG", "id=${id}, event=${event}")
        if (event == 1003) {
            Log.e("TAG", "====event === 1003")
            keepPlayThreadLock.let {
                synchronized(it) {
                    Log.d("TAG", "====p2p链路断开, event=$event.")
                    it.notify()
                }
            } // 唤醒守护线程
            launch(Dispatchers.Main) {
                var content = "$id 通道断开，正在重连"
                Toast.makeText(this@VideoPreviewAct, content, Toast.LENGTH_SHORT).show()
            }
        } else if (event == 1004 || event == 1005) {
//            connectTime = System.currentTimeMillis() - connectStartTime
            if (event == 1004) {
                Log.e("TAG", "====event === 1004")
            }
        } else if (event == 1010) {
            Log.e("TAG", "====event === 1010, 校验失败，info撞库防止串流： $msg")
        }
    }

    override fun avDataRecvHandle(id: String?, data: ByteArray?, len: Int) {
    }

    override fun avDataCloseHandle(id: String?, msg: String?, errorCode: Int) {
    }

    override fun onDeviceMsgArrived(id: String?, data: ByteArray?, len: Int): String {
        return "app reply to device"
    }

    override fun onInfo(mp: IMediaPlayer?, what: Int, extra: Int): Boolean {
        return true
    }

    override fun onInfoSEI(mp: IMediaPlayer?, what: Int, extra: Int, sei_content: String?): Boolean {
        return false
    }

    override fun onInfoAudioPcmData(mp: IMediaPlayer?, arrPcm: ByteArray?, length: Int) {
    }


    private fun finishPlayer() {
//        if (binding.radioTalk.isChecked) speakAble(false)
//        if (binding.radioRecord.isChecked) {
//            videoPlayer.stopRecord()
//            CommonUtils.refreshVideoList(this@VideoPreviewActivity, filePath)
//        }
        if (::videoPlayer.isInitialized) {
            videoPlayer.release()
        }

//        countDownLatchs.clear()
        // 关闭守护线程
        keepAliveThreadRuning = false
        keepPlayThreadLock?.let {
            synchronized(it) {
                it.notify()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        finishPlayer()
        XP2P.stopService("${AppData.productId}/${eventPresenter.getDeviceName()}")
        XP2P.setCallback(null)
        cancel()
//        volumeChangeObserver?.unregisterReceiver();
    }
}